package com.apes.scm.account.account.model;

import com.apes.framework.jpa.DefaultPersistListener;
import com.apes.framework.jpa.Model;
import com.apes.framework.jpa.comment.Comment;
import com.apes.framework.jpa.generator.ApesGenerator;
import com.apes.framework.util.ApesConst;
import com.apes.scm.contract.model.Contract;
import com.apes.scm.account.tax.model.Tax;
import com.apes.scm.masterdata.frame.model.Dept;
import com.apes.scm.masterdata.party.model.PartyRole;
import com.apes.scm.masterdata.product.model.Product;
import com.apes.scm.masterdata.product.model.ProductUom;
import lombok.Getter;
import lombok.Setter;
import org.hibernate.annotations.DynamicInsert;
import org.hibernate.annotations.DynamicUpdate;
import org.hibernate.annotations.SelectBeforeUpdate;

import javax.persistence.*;
import java.util.Date;

/**
 * 功能：商品价值库存（批次）
 *
 * @author xul
 * @create 2018-03-11 10:09
 */
@Getter
@Setter
@SelectBeforeUpdate
@DynamicInsert
@DynamicUpdate
@Entity
@EntityListeners(DefaultPersistListener.class)
@Table(name = InventoryBatch.CONST_TABLE_NAME, indexes = {
        @Index(columnList = "company_id, supplier_id, product_id"),
        @Index(columnList = "company_id, product_id"),
        @Index(columnList = "batch_number")})
public class InventoryBatch extends Model {
    public static final String CONST_TABLE_NAME = "acc_inventory_batch";

    @Id
    @Column(name = "id")
    @ApesGenerator(code = CONST_TABLE_NAME, name = "商品价值库存（批次）")
    @Comment("批次号")
    private long id;  //批次号

    @Column(name = "batch_number", length = 32, nullable = false)
    @Comment("批次内码")
    private long batchNumber;  //批次内码

    @Column(name = "batch_serial", nullable = false)
    @Comment("批次序号")
    private Integer batchSerial = 0;  //批次序号

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "company_id", referencedColumnName = "id", nullable = false)
    @Comment("公司编码")
    private PartyRole company;  //公司编码

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "dept_id", referencedColumnName = "id", nullable = false)
    @Comment("采购部门")
    private Dept dept; //采购部门

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "contract_id", referencedColumnName = "id")
    @Comment("采购合同")
    private Contract contract; //采购合同

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "supplier_id", referencedColumnName = "id", nullable = false)
    @Comment("供应商")
    private PartyRole supplier; //供应商

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "cooperation_id", referencedColumnName = "id", nullable = false)
    @Comment("采购合作方式")
    private Cooperation cooperation; //采购合作方式

    @Column(name = "protocol_type", nullable = false)
    @Comment("采购协议属性")
    private Integer protocolType = 0;  //采购协议属性

    @Column(name = "protocol", length = 32, nullable = false)
    @Comment("采购协议号")
    private String protocol = "0";  //采购协议号

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "original_supplier_id", referencedColumnName = "id")
    @Comment("原供应商")
    private PartyRole originalSupplier;

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_id", referencedColumnName = "id", nullable = false)
    @Comment("商品编码")
    private Product product;  //商品编码

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "product_uom_id", referencedColumnName = "id", nullable = false)
    @Comment("计量单位")
    private ProductUom uom; //计量单位

    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "tax_id", referencedColumnName = "id", nullable = false)
    @Comment("税率")
    private Tax tax; //税率

    @Column(name = "tax_cost_price", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("含税成本单价")
    private double taxCostPrice = 0.0;  //含税成本单价

    @Column(name = "no_tax_cost_price", nullable = false, columnDefinition = ApesConst.FIELD_MONEY_16_4_0)
    @Comment("无税成本单价")
    private double noTaxCostPrice = 0.0;  //无税成本单价

    @Column(name = "purchase_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("采购入库数量")
    private double purchaseQty = 0.0;  //采购入库数量

    @Column(name = "purchase_return_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("采购退货数量")
    private double purchaseReturnQty = 0.0;  //采购退货数量

    @Column(name = "price_change_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("变价数量")
    private double priceChangeQty = 0.0;   //变价数量

    @Column(name = "sales_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("销售数量")
    private double salesQty = 0.0;  //销售数量

    @Column(name = "profit_and_loss_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("损益数量")
    private double profitAndLossQty = 0.0;  //损益数量

    @Column(name = "balance_qty", nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("结存数量")
    private double balanceQty = 0.0;  //结存数量

    @Column(name = "frost_qty",  nullable = false, columnDefinition = ApesConst.FIELD_QTY_16_4_0)
    @Comment("冻结数量")
    private double frostQty = 0.0;  //冻结数量

    @Column(name = "purchase_in_date")
    @Comment("入库日期")
    private Date purchaseInDate;  //入库日期

    @Column(name = "expiration_date")
    @Comment("有效期限")
    private Date expirationDate;  //有效期限

    @Transient
    private String voucherOrigin; // 返厂显示用

    @Transient
    private double usableQty; // 商品库存可用数

    @Transient
    private double canReturnQty; // 可退数量

    @Transient
    private double transformBalanceQty; // 转换单位后的商品库存可用数

    @Transient
    private double transformPrice; //转换后的单价

    @Transient
    private ProductUom transferUom; //转储计量单位

    @Transient
    private double factor;
    /**
     * 功能：计算无税库存单价
     */
    public void computeExcludedPriceUnit() {
        double price = this.taxCostPrice;
        if (this.getTax() != null) {
            price = (double) this.getTax().computeAll(this.getCompany(), price, 1.0).get("totalExcluded");
        }
        noTaxCostPrice = price;
    }

    @Transient
    private double canPriceChangeQty; // 可变价数量
    public double getCanPriceChangeQty() {
        return this.getPurchaseQty()-this.getPurchaseReturnQty()+this.getPriceChangeQty();
    }

    /*
     * 功能：更新结存数量
     */
    public void changeBalanceQty(double changeQty) {
        this.balanceQty += changeQty;
        if (this.balanceQty < 0) throw new RuntimeException("批次内码["+ id + "]结存数量不允许小于零！商品：" + this.product.getId());
        if (this.balanceQty < this.frostQty) throw new RuntimeException("批次内码["+ id + "]冻结数量不能大于结存数量！商品：" + this.product.getId());
    }


    /*
     * 功能：更新冻结数量
     */
    public void changeFrostQty(double changeQty) {
        this.frostQty += changeQty;
        if(this.frostQty < 0) {
            throw new RuntimeException("批次内码[" + id + "]冻结数量不允许小于零！商品：" + this.product.getId());
        }
        if(this.frostQty > this.balanceQty) {
            throw new RuntimeException("批次内码[" + id + "]冻结数量不能大于结存数量！商品：" + this.product.getId());
        }
    }

    /*
     * 功能：更新采购退货数量
     */
    public void changePurchaseReturnQty(double changeQty) {
        this.purchaseReturnQty += changeQty;
    }

    /*
     * 功能：更新销售数量
     */
    public void changeSalesQty(double changeQty) {
        this.salesQty += changeQty;
        if(this.salesQty < 0) throw new RuntimeException("批次内码["+ id + "]销售数量不允许小于零！商品：" + this.product.getId());
        if(this.salesQty > this.purchaseQty +  this.priceChangeQty + this.profitAndLossQty - this.purchaseReturnQty) throw new RuntimeException("批次内码["+ id + "]销售数量不允许大于总入库数量！商品：" + this.product.getId());
    }

}
